package com.mmall.demo2.config;


import com.google.common.collect.Maps;
import com.mmall.demo2.shiro.AuthRealm;
import com.mmall.demo2.shiro.CredentialMatcher;
import com.mmall.demo2.shiro.RedisSessionDao;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

/**
 * @Author: jiaru
 * @Description: shiro 配置类：用于完成 shiro 配置
 * @Date: Created on 2018/10/31
 * @Modify:
 */
@Configuration
public class ShiroConfiguration {

    /***************** shiro 基础配置 *****************/
    /**
     * 配置shiro拦截器
     * @param manager 已在 Spring 容器中注册的“安全管理器”
     * @return
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
        // 定义shiro拦截器工厂bean
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();

        // 设置安全管理器
        bean.setSecurityManager(manager);

        // 设置登陆url
        bean.setLoginUrl("/login");
        // 设置登陆跳转后的url
        bean.setSuccessUrl("/index");
        // 设置无权限访问的url
        bean.setUnauthorizedUrl("/unauthorized");

        // 定义拦截规则
        LinkedHashMap<String, String> definitionMap = Maps.newLinkedHashMap();
        definitionMap.put("/index", "authc");
        definitionMap.put("/login", "anon");
        definitionMap.put("/loginUser", "anon");
        definitionMap.put("/admin", "roles[admin]");
        definitionMap.put("/edit", "perms[edit]");
        definitionMap.put("/query", "perms[query]");
        definitionMap.put("/druid/**", "anon");
        definitionMap.put("/**", "user");
        // 设置拦截规则
        bean.setFilterChainDefinitionMap(definitionMap);

        return bean;
    }

    /**
     * 配置安全管理器
     * @param authRealm 已在 Spring 容器中注册的“用户域”
     * @param sessionManager 自定义的“会话管理器”
     * @return
     */
    @Bean("securityManager")
    public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm,
                                           @Qualifier("sessionManager") WebSessionManager sessionManager) {
        // 新建web管理器
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();

        // 设置“用户域”
        manager.setRealm(authRealm);

        // 设置 session 管理器：用于单点登陆
        manager.setSessionManager(sessionManager);

        return manager;
    }

    /********* ========= 配置 shiro Realm（用户域） =========== *********/
    /**
     * 配置用户域
     * @param matcher 已在 Spring 容器中注册的“密码校验类”
     * @return
     */
    @Bean("authRealm")
    public AuthRealm authRealm(@Qualifier("credentialMatcher") CredentialMatcher matcher) {
        // 定义用户域
        AuthRealm authRealm = new AuthRealm();

        // 设置密码校验规则
        authRealm.setCredentialsMatcher(matcher);

        // 设置缓存管理器
        authRealm.setCacheManager(new MemoryConstrainedCacheManager());

        return authRealm;
    }

    /**
     * 配置shiro密码校验类
     * @return
     */
    @Bean("credentialMatcher")
    public CredentialMatcher credentialMatcher() {
        return new CredentialMatcher();
    }

    /********* ========= 配置 shiro session管理器：用于单点登陆 =========== *********/
    /**
     * 设置 session 管理器
     * @param sessionDAO
     * @return
     */
    @Bean("sessionManager")
    public WebSessionManager sessionManager(@Qualifier("sessionDAO") SessionDAO sessionDAO,
                                            @Qualifier("sessionCookie") SimpleCookie cookie) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();

        // 自动删除无效 session
        sessionManager.setDeleteInvalidSessions(true);

        // 设置 session 超时时间，30 分钟超时
        sessionManager.setGlobalSessionTimeout(30 * 60 * 1000);

        // 设置 sessionDao
        sessionManager.setSessionDAO(sessionDAO);

        // 设置 cookie 信息
        sessionManager.setSessionIdCookie(cookie);

        return sessionManager;
    }

    /**
     * 设置用户 cookie 中 sessionId 的信息
     * @return
     */
    @Bean("sessionCookie")
    public SimpleCookie sessionIdCookie() {
        // 创建 Cookie 类，并设置名称
        SimpleCookie cookie = new SimpleCookie("session.id");

        // 不允许通过脚本访问 cookie。备注：无法防御所有脚本攻击，但可提高一定的安全性
        cookie.setHttpOnly(true);
        // 设置域名
        // cookie.setDomain("/");
        // 设置作用域
        cookie.setPath("/");
        return cookie;
    }

    /**
     * 设置 session 操作器
     * @return
     */
    @Bean("sessionDAO")
    public SessionDAO sessionDAO() {
        return new RedisSessionDao();
    }



    /***************** shiro && spring 关联 *****************/
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(manager);

        return advisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);

        return creator;
    }


}
